
`ifndef ID_V
`define ID_V


`include "defines.v"

module id(
	//from instf_id
	input  wire[`InstAddrWidth - 1 : 0] inst_addr_i,
	input  wire[`InstWidth - 1 : 0] 	inst_i,
	
	// to regs 
	output reg[`RegAddrWidth - 1 : 0] 	reg1_raddr_o,
	output reg[`RegAddrWidth - 1 : 0] 	reg2_raddr_o,
	// from regs
	input  wire[`RegDataWidth - 1 : 0] 	reg1_rdata_i,
	input  wire[`RegDataWidth - 1 : 0] 	reg2_rdata_i,
	
	//to id_ex
	output reg[`InstAddrWidth - 1 : 0] 	inst_addr_o,
	output reg[`InstWidth - 1 : 0] 		inst_o,
	output reg[`RegAddrWidth - 1 : 0]  	reg_waddr_o,	
	output reg 		 					reg_wen_o,
	// output reg[`RegDataWidth - 1 : 0] reg1_rdata_o,
	// output reg[`RegDataWidth - 1 : 0] reg2_rdata_o,
	output reg[`OPWidth - 1 : 0] 		op1_o,	
	output reg[`OPWidth - 1 : 0] 		op2_o,
	output reg[`OPWidth - 1 : 0] 		op1_jump_o,
	output reg[`OPWidth - 1 : 0] 		op2_jump_o,

	// to mem
	output reg							mem_rreq_o,
	output reg[`MemAddrWidth - 1 : 0]	mem_raddr_o
);

wire[6:0] opcode; 
wire[2:0] funct3;
wire[6:0] funct7;
wire[4:0] rd	; 
wire[4:0] rs1	;
wire[4:0] rs2	;
wire[4:0] shamt ;
	
assign opcode = inst_i[6:0];
assign funct3 = inst_i[14:12];
assign funct7 = inst_i[31:25];
assign rd 	  = inst_i[11:7];
assign rs1 	  = inst_i[19:15];
assign rs2 	  = inst_i[24:20];
assign shamt  = inst_i[24:20];

always @(*)begin
	inst_o  	= inst_i;
	inst_addr_o = inst_addr_i;  
	// reg1_rdata_o = reg1_rdata_i;
	// reg2_rdata_o = reg2_rdata_i;
	
	case(opcode)
		`INST_TYPE_R, `INST_TYPE_M : begin
			if((funct7 == 7'b0000000) || (funct7 == 7'b0100000)) begin
				case(funct3)
					`INST_ADD, `INST_SUB, `INST_SLT, `INST_SLTU, `INST_XOR, `INST_OR, `INST_AND : begin
						reg1_raddr_o 	= rs1;
						reg2_raddr_o 	= rs2;
						op1_o 	   		= reg1_rdata_i;
						op2_o      		= reg2_rdata_i;
						reg_waddr_o  	= rd;
						reg_wen_o    	= 1'b1;
					end
					`INST_SLL, `INST_SRL, `INST_SRA : begin // 单独拿出来，方便ex中ALU复用
						reg1_raddr_o 	= rs1;
						reg2_raddr_o 	= rs2;
						op1_o 	   		= reg1_rdata_i;
						op2_o      		= {27'b0, reg2_rdata_i[4:0]}; // 主要就是这里
						reg_waddr_o  	= rd;
						reg_wen_o    	= 1'b1;
					end

					default : begin
						reg1_raddr_o 	= `REG_X0_ADDR;
						reg2_raddr_o 	= `REG_X0_ADDR;
						op1_o 	   		= `OP_ZERO;
						op2_o      		= `OP_ZERO;
						reg_waddr_o  	= `REG_X0_ADDR;
						reg_wen_o    	= 1'b0;			
					end
				endcase	
			end
			else if(funct7 == 7'b0000001) begin
				case(funct3)
					`INST_MUL, `INST_MULH, `INST_MULHSU, `INST_MULHU : begin
						reg1_raddr_o 	= rs1;
						reg2_raddr_o 	= rs2;
						op1_o 	   		= reg1_rdata_i;
						op2_o      		= reg2_rdata_i;
						reg_waddr_o  	= rd;
						reg_wen_o    	= 1'b1;	
					end
					`INST_DIV, `INST_DIVU, `INST_REM, `INST_REMU : begin
						reg1_raddr_o 	= rs1;
						reg2_raddr_o 	= rs2;
						op1_o 	   		= reg1_rdata_i;
						op2_o      		= reg2_rdata_i;
						op1_jump_o		= inst_addr_i;
						op2_jump_o		= 32'h4;
						reg_waddr_o  	= rd;
						reg_wen_o    	= 1'b1;	// 1'b0
					end
					default : begin
						reg1_raddr_o 	= `REG_X0_ADDR;
						reg2_raddr_o 	= `REG_X0_ADDR;
						op1_o 	   		= `OP_ZERO;
						op2_o      		= `OP_ZERO;
						reg_waddr_o  	= `REG_X0_ADDR;
						reg_wen_o    	= 1'b0;	
					end
				endcase
			end
			else begin
				op1_jump_o = `OP_ZERO;
				op2_jump_o = `OP_ZERO;
				mem_rreq_o 	= 1'b0;
				mem_raddr_o	= `MEM_ZERO_ADDR;
			end	
		end
		`INST_TYPE_L : begin
			case(funct3) 
				`INST_LB, `INST_LH, `INST_LW, `INST_LBU, `INST_LHU : begin
					reg1_raddr_o 	= rs1;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= `OP_ZERO;
					op2_o      		= `OP_ZERO;
					op1_jump_o 		= `OP_ZERO;
					op2_jump_o 		= `OP_ZERO;
					reg_waddr_o  	= rd;
					reg_wen_o    	= 1'b1;
					mem_rreq_o 		= 1'b1;
					mem_raddr_o		= rs1 + {{20{inst_i[31]}}, inst_i[31:20]};
				end
				default : begin
					reg1_raddr_o 	= `REG_X0_ADDR;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= `OP_ZERO;
					op2_o      		= `OP_ZERO;
					op1_jump_o 		= `OP_ZERO;
					op2_jump_o 		= `OP_ZERO;
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;
					mem_rreq_o 		= 1'b0;
					mem_raddr_o		= `MEM_ZERO_ADDR;
				end
			endcase
		end
		`INST_TYPE_I : begin
			op1_jump_o 	= `OP_ZERO;
			op2_jump_o 	= `OP_ZERO;
			mem_rreq_o 	= 1'b0;
			mem_raddr_o	= `MEM_ZERO_ADDR;
			case(funct3)
				`INST_ADDI, `INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI : begin
					reg1_raddr_o 	= rs1;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= reg1_rdata_i;
					op2_o      		= {{20{inst_i[31]}}, inst_i[31:20]};
					reg_waddr_o  	= rd;
					reg_wen_o    	= 1'b1;
				end
				`INST_SLLI, `INST_SRLI, `INST_SRAI : begin
					reg1_raddr_o 	= rs1;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= reg1_rdata_i;
					op2_o      		= {27'b0, shamt};
					reg_waddr_o  	= rd;
					reg_wen_o    	= 1'b1;
				end

				default : begin
					reg1_raddr_o 	= `REG_X0_ADDR;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= `OP_ZERO;
					op2_o      		= `OP_ZERO;
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;				
				end
			endcase	
		end
		`INST_TYPE_S : begin
			case(funct3) 
				`INST_SB, `INST_SH, `INST_SW : begin
					reg1_raddr_o 	= rs1;
					reg2_raddr_o 	= rs2;
					op1_o 	   		= reg1_rdata_i;
					op2_o      		= reg2_rdata_i;
					op1_jump_o 		= reg1_rdata_i;
					op2_jump_o 		= {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]};
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;
					mem_rreq_o 		= 1'b0;
					mem_raddr_o		= `MEM_ZERO_ADDR;
				end
				default : begin
					reg1_raddr_o 	= `REG_X0_ADDR;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= `OP_ZERO;
					op2_o      		= `OP_ZERO;
					op1_jump_o 		= `OP_ZERO;
					op2_jump_o 		= `OP_ZERO;
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;
					mem_rreq_o 		= 1'b0;
					mem_raddr_o		= `MEM_ZERO_ADDR;
				end
			endcase
		end
		`INST_TYPE_B : begin
			mem_rreq_o 	= 1'b0;
			mem_raddr_o	= `MEM_ZERO_ADDR;
			case(funct3)
				`INST_BEQ, `INST_BNE, `INST_BLT, `INST_BGE, `INST_BLTU, `INST_BGEU : begin
					reg1_raddr_o 	= rs1;
					reg2_raddr_o 	= rs2;
					op1_o 	   		= reg1_rdata_i;
					op2_o      		= reg2_rdata_i;
					op1_jump_o 		= inst_addr_i;
					op2_jump_o 		= {{19{inst_i[31]}}, inst_i[31], inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;				
				end

				default : begin
					reg1_raddr_o 	= `REG_X0_ADDR;
					reg2_raddr_o 	= `REG_X0_ADDR;
					op1_o 	   		= `OP_ZERO;
					op2_o      		= `OP_ZERO;
					op1_jump_o 		= `OP_ZERO;
					op2_jump_o 		= `OP_ZERO;
					reg_waddr_o  	= `REG_X0_ADDR;
					reg_wen_o    	= 1'b0;							
				end
			endcase
		end
		`INST_LUI : begin
			reg1_raddr_o 	= `REG_X0_ADDR;
			reg2_raddr_o 	= `REG_X0_ADDR;
			op1_o 	   		= {inst_i[31:12], 12'b0};
			op2_o      		= `OP_ZERO;
			op1_jump_o 		= `OP_ZERO;
			op2_jump_o 		= `OP_ZERO;
			reg_waddr_o  	= rd;
			reg_wen_o    	= 1'b1;
			mem_rreq_o 		= 1'b0;
			mem_raddr_o		= `MEM_ZERO_ADDR;		
		end
		`INST_AUIPC : begin
			reg1_raddr_o 	= `REG_X0_ADDR;
			reg2_raddr_o 	= `REG_X0_ADDR;
			op1_o 	   		= {inst_i[31:12], 12'b0};
			op2_o      		= inst_addr_i;
			op1_jump_o 		= `OP_ZERO;
			op2_jump_o 		= `OP_ZERO;
			reg_waddr_o  	= rd;
			reg_wen_o    	= 1'b1;
			mem_rreq_o 		= 1'b0;
			mem_raddr_o		= `MEM_ZERO_ADDR;	
		end
		`INST_JAL : begin
			reg1_raddr_o 	= `REG_X0_ADDR;
			reg2_raddr_o 	= `REG_X0_ADDR;
			op1_o 	   		= inst_addr_i;
			op2_o      		= 32'h4;
			op1_jump_o 		= inst_addr_i;
			op2_jump_o 		= {{11{inst_i[31]}}, inst_i[31], inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};;
			reg_waddr_o  	= rd;
			reg_wen_o    	= 1'b1;
			mem_rreq_o 		= 1'b0;
			mem_raddr_o		= `MEM_ZERO_ADDR;						
		end
		`INST_JALR : begin
			reg1_raddr_o 	= rs1;
			reg2_raddr_o 	= `REG_X0_ADDR;
			op1_o 	   		= inst_addr_i;
			op2_o      		= 32'h4;
			op1_jump_o 		= reg1_rdata_i;
			op2_jump_o 		= {{20{inst_i[31]}}, inst_i[31:20]};
			reg_waddr_o  	= rd;
			reg_wen_o    	= 1'b1;
			mem_rreq_o 		= 1'b0;
			mem_raddr_o		= `MEM_ZERO_ADDR;	
		end	

		default : begin
			reg1_raddr_o 	= `REG_X0_ADDR;
			reg2_raddr_o 	= `REG_X0_ADDR;
			op1_o 	   		= `OP_ZERO;
			op2_o      		= `OP_ZERO;
			op1_jump_o 		= `OP_ZERO;
			op2_jump_o 		= `OP_ZERO;
			reg_waddr_o  	= `REG_X0_ADDR;
			reg_wen_o    	= 1'b0;
			mem_rreq_o 		= 1'b0;
			mem_raddr_o		= `MEM_ZERO_ADDR;					
		end
	endcase
end

endmodule


`endif // ID_V